#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
#include <openssl/ssl.h>
#include <openssl/opensslv.h>

void onMessageCb(AMQP::TcpChannel* channel, const AMQP::Message& message, uint64_t deliveryTag, bool redelivered)
{
    std::string msg;
    msg.assign(message.body(), message.bodySize());
    std::cout << "接收消息" << msg << std::endl;
    channel->ack(deliveryTag);  // 通过消息的唯一标识 deliveryTag 对消息进行确认
}


int main()
{
    // 1. 底层网络通信框架的I/O事件监控句柄
    auto loop = EV_DEFAULT;

    // 2. 实例化libEvHandler句柄 --- 将AMQP框架与事件监控关联起来
    AMQP::LibEvHandler handler(loop);
    
    // 2-1 连接对象
    AMQP::Address address("amqp://root:weng9244@127.0.0.1:5672/");
    AMQP::TcpConnection connection(&handler, address);

    // 3. 信道对象
    AMQP::TcpChannel channel(&connection);

    // 4. 声明交换机
    channel.declareExchange("test-exchange", AMQP::ExchangeType::direct)
        .onError([](const char* message) {
            std::cout << "声明交换机失败：" << message << std::endl;
            exit(0);
        })
        .onSuccess([](){
            std::cout << "test-exchange 交换机创建成功！" << std::endl;
        });

    // 5. 声明队列
    channel.declareQueue("test-queue")
        .onError([](const char* message) {
            std::cout << "声明队列失败：" << message << std::endl;
            exit(0);
        })
        .onSuccess([](){
            std::cout << "test-queue 队列创建成功！" << std::endl;
        });

    // 6. 交换机和队列绑定
    channel.bindQueue("test-exchange", "test-queue", "test-queue-key")
        .onError([](const char* message) {
            std::cout << "test-exchange - test-queue 绑定失败：" << message << std::endl;
            exit(0);
        })
        .onSuccess([](){
            std::cout << "test-exchange - test-queue 绑定成功！" << std::endl;
        });

    // 7. 订阅队列消息 & 消息处理
    auto cb = std::bind(onMessageCb, &channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    channel.consume("test-queue", "consumer1")
        .onReceived(cb)     // 需要先调 onReceived 返回子类 DeferredConsumer, 才能继续通过其父类 Deferred 调用 onError(该接口只返回基类)
        .onError([](const char *message){
            std::cout << "订阅 test-queue 队列消息失败:" << message << std::endl;
            exit(0);
        }); 

    // 启动事件循环(阻塞)
    ev_run(loop, 0);

    return 0;
}